

function New-AesKey {
    Param(
        [Parameter(Mandatory = $false, Position = 1, ValueFromPipeline = $true)]
        [Int]$KeySize = 256
    )

    try {
        $AESProvider = New-Object "System.Security.Cryptography.AesManaged"
        $AESProvider.KeySize = $KeySize
        $AESProvider.GenerateKey()
        return [System.Convert]::ToBase64String($AESProvider.Key)
    }
    catch {
        Write-Error $_
    }
}

function New-AesFile {
    param(
        [Parameter(Position = 0, Mandatory = $True, HelpMessage = "Enter your need encrypt file")]
        [System.IO.FileInfo]$File,
        [string]$Key,
        [string]$Destination
    )
    if ([System.String]::IsNullOrEmpty($Destination)) {
        $Destination = $Path + ".crypt"
    }
    try {
        $EncryptionKey = [System.Convert]::FromBase64String($Key)
        $KeySize = $EncryptionKey.Length * 8
        $AESProvider = New-Object 'System.Security.Cryptography.AesManaged'
        $AESProvider.Mode = [System.Security.Cryptography.CipherMode]::CBC
        $AESProvider.BlockSize = 128
        $AESProvider.KeySize = $KeySize
        $AESProvider.Key = $EncryptionKey
    }
    Catch {
        Write-Error 'Unable to configure AES, verify you are using a valid key.'
        Return
    }
    Write-Verbose "Encryping $($File.FullName) with the $KeySize-bit key $Key"
    Try {
        $FileStreamReader = New-Object System.IO.FileStream($File.FullName, [System.IO.FileMode]::Open)
    }
    Catch {
        Write-Error "Unable to open $($File.FullName) for reading.`n$_"
        return 1
    }
    Try {
        $FileStreamWriter = New-Object System.IO.FileStream($Destination, [System.IO.FileMode]::Create)
    }
    Catch {
        Write-Error "Unable to open $Destination for writing."
        $FileStreamReader.Close()
        return 1
    }
    $AESProvider.GenerateIV()
    $FileStreamWriter.Write([System.BitConverter]::GetBytes($AESProvider.IV.Length), 0, 4)
    $FileStreamWriter.Write($AESProvider.IV, 0, $AESProvider.IV.Length)
    Write-Verbose "Encrypting $($File.FullName) with an IV of $([System.Convert]::ToBase64String($AESProvider.IV))"
    try {
        $Transform = $AESProvider.CreateEncryptor()
        $CryptoStream = New-Object System.Security.Cryptography.CryptoStream($FileStreamWriter, $Transform, [System.Security.Cryptography.CryptoStreamMode]::Write)
        [Int]$Count = 0
        [Int]$BlockSizeBytes = $AESProvider.BlockSize / 8
        [Byte[]]$Data = New-Object Byte[] $BlockSizeBytes
        Do {
            $Count = $FileStreamReader.Read($Data, 0, $BlockSizeBytes)
            $CryptoStream.Write($Data, 0, $Count)
        }
        While ($Count -gt 0)
    
        #Close open files
        $CryptoStream.FlushFinalBlock()
        $CryptoStream.Close()
        $FileStreamReader.Close()
        $FileStreamWriter.Close()

        Write-Verbose "Successfully encrypted $($File.FullName)"
    }
    catch {
        Write-Error "Failed to encrypt $($File.FullName)."
        $CryptoStream.Close()
        $FileStreamWriter.Close()
        $FileStreamReader.Close()
        Remove-Item $Destination
        return 1
    }
    return 0
}
function Restore-AesFile {
    param(
        [System.IO.FileInfo]$File,
        [string]$Key,
        [string]$Destination
    )
    try {
        $EncryptionKey = [System.Convert]::FromBase64String($Key)
        $KeySize = $EncryptionKey.Length * 8
        $AESProvider = New-Object 'System.Security.Cryptography.AesManaged'
        $AESProvider.Mode = [System.Security.Cryptography.CipherMode]::CBC
        $AESProvider.BlockSize = 128
        $AESProvider.KeySize = $KeySize
        $AESProvider.Key = $EncryptionKey
    }
    Catch {
        Write-Error 'Unable to configure AES, verify you are using a valid key.'
        Return
    }
    Write-Verbose "Encryping $($File.FullName) with the $KeySize-bit key $Key"

    #Open file to decrypt
    Try {
        $FileStreamReader = New-Object System.IO.FileStream($File.FullName, [System.IO.FileMode]::Open)
    }
    Catch {
        Write-Error "Unable to open $($File.FullName) for reading."
        return 1
    }
    
    Try {
        $FileStreamWriter = New-Object System.IO.FileStream($Destination, [System.IO.FileMode]::Create)
    }
    Catch {
        Write-Error "Unable to open $DestinationFile for writing."
        $FileStreamReader.Close()
        return 1
    }

    #Get IV
    try {
        [Byte[]]$LenIV = New-Object Byte[] 4
        $FileStreamReader.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null
        $FileStreamReader.Read($LenIV, 0, 3) | Out-Null
        [Int]$LIV = [System.BitConverter]::ToInt32($LenIV, 0)
        [Byte[]]$IV = New-Object Byte[] $LIV
        $FileStreamReader.Seek(4, [System.IO.SeekOrigin]::Begin) | Out-Null
        $FileStreamReader.Read($IV, 0, $LIV) | Out-Null
        $AESProvider.IV = $IV
    }
    catch {
        Write-Error 'Unable to read IV from file, verify this file was made using the included New-AesFile function.'
        return 1
    }

    Write-Verbose "Decrypting $($File.FullName) with an IV of $([System.Convert]::ToBase64String($AESProvider.IV))"

    #Decrypt
    try {
        $Transform = $AESProvider.CreateDecryptor()
        [Int]$Count = 0
        [Int]$BlockSizeBytes = $AESProvider.BlockSize / 8
        [Byte[]]$Data = New-Object Byte[] $BlockSizeBytes
        $CryptoStream = New-Object System.Security.Cryptography.CryptoStream($FileStreamWriter, $Transform, [System.Security.Cryptography.CryptoStreamMode]::Write)
        Do {
            $Count = $FileStreamReader.Read($Data, 0, $BlockSizeBytes)
            $CryptoStream.Write($Data, 0, $Count)
        }
        While ($Count -gt 0)

        $CryptoStream.FlushFinalBlock()
        $CryptoStream.Close()
        $FileStreamWriter.Close()
        $FileStreamReader.Close()

        Write-Verbose "Successfully decrypted $($File.FullName)"
    }
    catch {
        Write-Error "Failed to decrypt $($File.FullName)."
        $CryptoStream.Close()
        $FileStreamWriter.Close()
        $FileStreamReader.Close()
        Remove-Item $Destination
        return 1
    }        
    return 0
}

Export-ModuleMember -Function New-AesKey
Export-ModuleMember -Function New-AesFile
Export-ModuleMember -Function Restore-AesFile